; Completar aqui las funciones sin el _C final (Ejemplo: "copiar" en vez de "copiar_C")
; Recuerde reemplazar las llamadas a las funciones en C por estas nuevas

%include "negador.mac"

; void copiar_C ( Uint8* img1, int screen_w, int screen_h, Uint8* img2);
global copiar

; void copiarInvertido_C ( Uint8* img1, int screen_w, int screen_h, Uint8* img2);
global copiarInvertido

; void zoom_C(Uint8* foto, Uint32 w, Uint32 h, Uint8* zoom);
global zoom

; void blit(Uint8 *screen, int s_w, int s_h, Uint8 *image, int w, int h, int x, int y, Color color_off)
global blit_asm

; bool negative_asm(Uint8* screen, Uint32 w, Uint32 h);
global negative_asm

;void generarPlasma_asm(Uint8* screen->pixels, int screen_w, int screen_h)
global generarPlasma_asm

extern horizontal_0, horizontal_1, vertical_0, vertical_1, colores, vel_vertical_0, vel_vertical_1, vel_horizontal_0, vel_horizontal_1

%define ptr_img_actual [ebp - 4]
%define ptr_img1 [ebp + 8]
%define screen_w [ebp + 12]
%define screen_h [ebp + 16]
%define ptr_img2 [ebp + 20]
%define image_w [ebp + 24]
%define image_h [ebp + 28]
%define x [ebp + 32]
%define y [ebp + 36]
%define color_off [ebp + 40]
%define dos55H 0x00FF
%define unosH 0x0001



section .data

	unos: dd unosH,unosH,unosH,unosH
	dos55: dd dos55H,dos55H,dos55H,dos55H
	doubles64: dd 0x00000040, 0x00000040, 0x00000040, 0x00000040	;para comparar contra 64 a cada word dentro de un xmm.
	doubles128: dd 0x00000080, 0x00000080, 0x00000080, 0x00000080	;para comparar/sumar 128 a cada word dentro de un xmm.
	doubles192: dd 0x000000C0, 0x000000C0, 0x000000C0, 0x000000C0	;para comparar contra 192 a cada word dentro de un xmm.
	doubles256: dd 0x00000100, 0x00000100, 0x00000100, 0x00000100	;para comparar contra 256 a cada word dentro de un xmm.
	
	suma1prim:	dd 0x00000001, 0x00000001, 0x00000001, 0x00000001						;para sumar 1 al primer byte de cada dword de un xmm.
	suma1seg:	dd 0x00000100, 0x00000100, 0x00000100, 0x00000100						;para sumar 1 al primer y segundo byte de cada dword de un xmm.
	invertirprimbyte: dd 0x000000FF, 0x000000FF, 0x000000FF, 0x000000FF					;para invertir el primer byte de cada dword(es lo mismo que 255 - valor).(usar XOR)
	invertirprimysegbyte: dd 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF				;para invertir el primer byte de cada dword(es lo mismo que 255 - valor).(usar XOR)
	setearsegundo255: dd 0x0000FF00, 0x0000FF00, 0x0000FF00, 0x0000FF00					;para dejar en 255 el segundo byte de cada dword.(usar OR)
	setearterceroyultimo0: dd 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF	 		;para dejar en 0 el tercer y 4 byte de cada dword.(usar AND)
	setearsegundo0: dd 0xFFFF00FF, 0xFFFF00FF, 0xFFFF00FF, 0xFFFF00FF				 	;para dejar en 0 el tercer y 4 byte de cada dword.(usar AND)
	sumarultimo1: dd 0x01000000, 0x01000000, 0x01000000, 0x01000000 					;para sumar 1 el cuarto byte de cada dword.
	modulador: dd 0x000001FF,0x000001FF,0x000001FF,0x000001FF	


section .text


copiar:
	push ebp
	mov ebp, esp
	push edi
	push esi
	push ebx
	
empiezo:
	mov eax, screen_w ; Guardamos en eax el screen_w en bytes.
	mov ebx, screen_h ; Guardamos en edx la cantidad de filas screen_h.
	
	mul ebx  ; ahora tenemos en edx:eax la cantidad total de bytes.
	
	mov ebx, 64
	div ebx
	mov ecx, eax ; Guardamos el cociente en ecx.
	
	mov esi, ptr_img1
	mov edi, ptr_img2
	
	xor ebx, ebx
	
ciclo:
	movups xmm0, [esi]
	movups xmm1, [esi + 16]
	movups xmm2, [esi + 32]
	movups xmm3, [esi + 48]
	movups [edi], xmm0
	movups [edi + 16], xmm1
	movups [edi + 32], xmm2
	movups [edi + 48], xmm3
	add esi, 64
	add edi, 64
	add ebx, 1
	
	cmp ebx, ecx
	jne ciclo

	cmp edx, 0
	je NEAR fin
	
	mov ecx, edx
	
cicloresto:
	mov eax, [esi]
	mov [edi], eax
	add esi, 4
	add edi, 4
	loop cicloresto
	
	xor eax, eax

	jmp fin
	
	
copiarInvertido:
	push ebp
	mov ebp, esp
	push edi
	push esi
	push ebx
	
	xor edx, edx
	mov eax, screen_w
	mov ecx, screen_h
	mov esi, ptr_img1
	mov edi, ptr_img2
	
	mov ebx, 16   ; eax = cuantos bloques de xmm entran.
	div ebx       ; edx = el resto.
	
ciclofilas:
	shl eax, 4 ; Multiplico eax por 16.
	add esi, eax
	shr eax, 4
	
	push ecx
	mov ecx, edx ; Restauramos el resto.
	cmp ecx, 0
	je saltoresto
	
cicloresto2:
	mov ebx, [esi + ecx - 4]
	mov [edi], ebx
	add edi, 4
	sub ecx, 4
	cmp ecx, 0
	jne cicloresto2
	
saltoresto:
	mov ecx, eax
	
ciclocolumnas:
	movups xmm0, [esi - 16]
	pshufd xmm1, xmm0, 00011011b
	movups [edi], xmm1
	sub esi, 16
	add edi, 16
	loop ciclocolumnas
	
	; Ubicamos a esi en la siguiente fila.
	shl eax, 4 ; Multiplico eax por 16.
	add esi, eax
	shr eax, 4
	add esi, edx
	
	pop ecx
	loop ciclofilas
	
	xor eax, eax
	
	jmp fin
	
zoom:
	push ebp
	mov ebp, esp
	push edi
	push esi
	push ebx
	
	xor edx, edx
	mov eax, screen_w
	mov ecx, screen_h
	mov esi, ptr_img1
	mov edi, ptr_img2
	
	mov ebx, 16   ; eax = cuantos bloques de xmm entran.
	div ebx       ; edx = el resto.
	
ciclofilaszoom:
	push ecx
	
	shl eax, 4 ; Multiplico eax por 16.
	mov ebx, eax ; ebx = el ancho en bytes de la imagen.
	add ebx, edx
	shl ebx, 1 ; Multiplico por dos lo que calcule.
	shr eax, 4
	
	xor ecx, ecx
	
ciclocolumnaszoom:
	; Ver que hay que poner en ebx. para edi
	movups xmm0, [esi]
	movups xmm1, xmm0
	movups xmm2, xmm0
	punpckhdq xmm0, xmm1
	punpckldq xmm2, xmm1
	movups [edi], xmm2
	movups [edi + 16], xmm0
	movups [edi + ebx], xmm2
	movups [edi + ebx +16], xmm0
	add esi, 16
	add edi, 32
	inc ecx
	cmp ecx, eax
	jne ciclocolumnaszoom
	
	cmp edx, 0
	je saltorestozoom
	
	xor ecx, ecx
	push eax
cicloresto3:
	mov eax, [esi]
	mov [edi], eax
	mov [edi + 4], eax
	mov [edi + ebx], eax
	mov [edi + ebx + 4], eax
	add esi, 4
	add edi, 8
	add ecx, 4
	cmp ecx, edx
	jne cicloresto3
	pop eax
	
saltorestozoom:
		
	; Ubicamos a edi en la siguiente fila.
	add edi, ebx
	
	pop ecx
	loop ciclofilaszoom
	
	xor eax, eax
	
	jmp fin
	
	
blit_asm:
	push ebp
	mov ebp, esp
	push edi
	push esi
	push ebx
	
	; Seteamos la mascara en el registro xmm0.
	mov eax, color_off
	movd xmm0, eax
	pshufd xmm0, xmm0, 00000000b	;xmm0 = mascara para 4 colores.
	
	; Reposicionamos el puntero esi a la pantalla en el (x,y).
	xor edx,edx
	mov esi, ptr_img1
	mov eax, y
	mov ebx, screen_w
	shl ebx, 2
	mul ebx
	add esi, eax	;esi apunta al comienzo de la fila y.
	mov eax, x
	shl eax, 2
	add esi, eax	;esi apunta al (x,y) del screen.
	
	; Calculamos la cantidad de veces que puedo levantar con un registro de sse.
	xor edx, edx
	mov eax, image_w ; Guardamos en eax el image_w en pixeles.
	shl eax, 2 ; Guardamos en eax el image_w en bytes.
	mov ebx, eax ; Guardamos en ebx el image_w en bytes.
	mov ecx, 16	; cantidad de bloques de 16B.
	div ecx		; edx = ·bytes del resto.

	mov ecx, image_h ; Guardamos en ecx la cantidad de filas image_h.
	
	mov edi, ptr_img2
	
ciclofilasblit:	;ecx = altura de la imagen2.
	push ecx

	xor ecx, ecx
	
ciclocolumnasblit:
	movdqu xmm1, [esi] ; xmm1 = fondo.
	movdqu xmm3, [edi] ; xmm3 = personaje.
	movdqu xmm2, xmm0 ; xmm2 = mascara.
	
	pcmpeqd xmm2, xmm3
	
	pand xmm1, xmm2
	
	; obtenemos la negacion de la mascara y se la aplicamos al personaje.
	pcmpeqd xmm4, xmm4
	pxor xmm2, xmm4
	pand xmm3, xmm2	
	
	por xmm3, xmm1
	
	movdqu [edi], xmm3
	
	add esi, 16
	add edi, 16
	inc ecx
	cmp ecx, eax
	jne ciclocolumnasblit
	
	cmp edx, 0
	je saltorestoblit
	
	xor ecx, ecx
	push eax
	
cicloresto4:
	mov eax, [esi]
	;comparar con mascara
	
	mov [edi], eax
	add esi, 4
	add edi, 4
	add ecx, 1
	cmp ecx, edx
	jne cicloresto4
	pop eax
	
saltorestoblit:
	; Reubicamos a esi en el x de la fila siguiente.
	mov ecx, screen_w
	shl ecx, 2		;lo pasamos a bytes.
	sub ecx, ebx	;le restamos el ancho de la imagen.
	add esi, ecx
	
	pop ecx
	loop ciclofilasblit
	
	xor eax, eax
	
	jmp fin
	

negative_asm:
	push ebp
	mov ebp, esp
	push edi
	push esi
	push ebx
	
	mov esi, ptr_img1
	mov ecx, screen_h ; ecx = alto. iterador a lo alto.
	mov edx, screen_w ; edx = ancho. iterador a lo ancho.
	
	mov ebx, edx ; ebx = ancho.
	
	movdqu xmm6, [dos55] ; cargo 255s en el registo xmm6.
	movdqu xmm7, [unos] ; cargo unos en el registro xmm7.
	cvtdq2ps xmm7,xmm7
	cvtdq2ps xmm6,xmm6
	
	mov edi, edx ; edi = ancho de la imagen en pixels.
	shl edi, 2 ; edi= ancho de la imagen en bytes.
	mov eax, edi ; eax= ancho de la imagen en bytes.
	neg eax		
	
	pxor xmm4, xmm4 ; xmm4 = 0.
	
	pxor xmm0, xmm0 ; xmm0 = pixel arriba.
	pxor xmm1, xmm1 ; xmm1 = pixel izquierda.
	
cicloprimerafila:	
	movd xmm2, [esi + 4]  ; xmm2 = pixel derecha.
	movd xmm3, [esi + edi] ; xmm3 = pixel abajo.
	
	negador ; parametros: xmm0=arriba, xmm1=izq, xmm2=derecha, xmm3=abajo, xmm5=pixel negado
	
	movd xmm1, [esi] ; xmm1 = pixel izquierda.
	movd [esi], xmm5
	
	add esi, 4 ; Nos corremos al proximo pixel.
	
	dec edx
	cmp edx, 0
	jne cicloprimerafila

	; Hacemos el pixel del borde derecho.
	movd xmm3, [esi + edi] ; xmm3 = pixel abajo.
	pxor xmm2, xmm2 ; xmm1 = pixel derecha.
	
	negador
	
	movd xmm1, [esi]
	movd [esi], xmm5
	add esi, 4 
	dec ecx
	
	
ciclofilasnegative:
	
	mov edx, ebx ; ancho. iterador a lo ancho.
	pxor xmm1, xmm1 ; xmm1 = pixel izquierda.
	
ciclocolumnasnegative:
	
	movd xmm0, [esi + eax] ; xmm0 = pixel arriba.
	movd xmm2, [esi + 4]    ; xmm2 = pixel derecha.
	movd xmm3, [esi + edi]  ; xmm3 = pixel abajo.
	
	negador ; parametros: xmm0=arriba, xmm1=izq, xmm2=derecha, xmm3=abajo, xmm5=pixel negado
	
	movd xmm1, [esi] ; xmm1 = pixel izquierda.
	
	movd [esi], xmm5
	
	; Nos corremos al proximo pixel.
	add esi, 4
	dec edx
	cmp edx, 0
	jne ciclocolumnasnegative
	
	; Hacemos el pixel del borde derecho.
	movd xmm1, [esi-4] ; xmm1 = pixel izquierda.
	movd xmm0, [esi + eax ] ; xmm0 = pixel arriba.
	pxor xmm2, xmm2 		; xmm2 = pixel derecha.
	movd xmm3, [esi + edi]  ; xmm3 = pixel abajo.
	
	
	negador
	
	movd xmm1, [esi] ; xmm1 = pixel izquierda.
	movd [esi], xmm5
	
	dec ecx
	cmp ecx, 1
	jne ciclofilasnegative

	
	mov edx, ebx ; ancho. iterador a lo ancho.
	
	pxor xmm1, xmm1 ; xmm1 = pixel izquierda.
	pxor xmm3, xmm3 ; xmm3 = pixel abajo.
		
cicloultimafila:	
	movd xmm0, [esi + eax] ; xmm0 = pixel arriba.
	movd xmm2, [esi + 4]   ; xmm2 = pixel derecha.
		
	negador ; parametros: xmm0=arriba, xmm1=izq, xmm2=derecha, xmm3=abajo, xmm5=pixel negado
	
	movd xmm1, [esi] ; xmm1 = pixel izquierda.
	movd [esi], xmm5
	
	add esi, 4 ; Nos corremos al proximo pixel.
	
	dec edx
	cmp edx, 0
	jne cicloultimafila

	; Hacemos el pixel del borde derecho.
	movd xmm0, [esi + eax]  ; xmm0 = pixel arriba.
	pxor xmm2, xmm2 		; xmm1 = pixel derecha.
	
	negador
	movd [esi], xmm5
	
	xor eax, eax
	jmp fin



generarPlasma_asm:
	push ebp
	mov ebp, esp
	sub esp, 4
	push edi
	push esi
	push ebx
	
	mov eax, ptr_img1
	mov ptr_img_actual, eax
	
	xor eax, eax ; ax = vertical_0
	xor ebx, ebx ; bx = vertical_1
	xor esi, esi ; si = horizontal_0
	xor edi, edi ; di = horizontal_1
	
	mov si, [vel_horizontal_0]		; horizontal_0 = vel_horizontal_0
	
	mov edx, screen_h ; Guardamos en ebx la cantidad de filas screen_h.
	
cicloplasmafilas:
	push edx
	
	mov ax, [vel_vertical_0]	;vertical_0 = vel_vertical_0
	mov bx, 0					;vertical_1 = 1
	
	mov edx, colores
	
	mov ecx, screen_w 	; Guardamos en eax el screen_w en pixeles.
	shl ecx, 2			; Guardamos en eax el screen_w en bytes.
	shr ecx, 4   		; ecx = cuantos bloques de xmm entran en el ancho de la pantalla.
	
	and si, 0x01FF		; lo deja en modulo 512.
	and di, 0x01FF		; lo deja en modulo 512.	
	
		
cicloplasmacolumnas:
	and ax, 0x01FF		; lo deja en modulo 512.
	and bx, 0x01FF		; lo deja en modulo 512.		
	
	; Generamos los X en xmm1 (x = colores[vertical_0] + colores[horizontal_0] + colores[vertical_1] + colores[horizontal_1])
	
	movdqu xmm0, [edx + eax * 4]
	movdqu xmm1, [edx + ebx * 4]
	movdqu xmm2, [edx + esi * 4]
	movdqu xmm3, [edx + edi * 4]	
	
	pshufd xmm2, xmm2, 00000000b
	pshufd xmm3, xmm3, 00000000b
		
	paddd xmm1, xmm0
	paddd xmm1, xmm2
	paddd xmm1, xmm3     	; xmm1 = | X0 | X1 | X2 | X3 |
	
		
	; Generamos los index en xmm1 (index = 128 + (x >> 4))
	psrad xmm1, 4			; shift logico empaquetado a derecha de a doubles. (pslld es a izquierda).
	movdqu xmm3, [doubles128]
	paddd xmm1, xmm3		; xmm1 = | I0 | I1 | I2 | I3 | 
	movdqu xmm7, xmm1		; me lo copio en xmm7
	
	movdqu xmm6, [invertirprimbyte]
	pand xmm7, xmm6
	
	pslld xmm1, 2			; xmm1 = |I0 << 2|I1 << 2|I2 << 2|I3 << 2|
	
	pshufd xmm2, xmm1, 00000000b
	pshufd xmm3, xmm1, 01010101b
	pshufd xmm4, xmm1, 10101010b
	pshufd xmm5, xmm1, 11111111b
	
	movdqu xmm6, [invertirprimbyte]
	pand xmm2, xmm6
	pand xmm3, xmm6
	pand xmm4, xmm6
	pand xmm5, xmm6
	
	packusdw xmm2, xmm3
	packusdw xmm4, xmm5
	packuswb xmm2, xmm4
	
	movdqu xmm1, xmm2	; xmm1 = |I0<<2|I0<<2|I0<<2|I0<<2|I1<<2|I1<<2|I1<<2|I1<<2|I2<<2|I2<<2|I2<<2|I2<<2|I3<<2|I3<<2|I3<<2|I3<<2|
		
	movdqu xmm3, [suma1prim]
	paddb xmm1, xmm3				;sumamos 1 al primer byte de cada dword.
	
	movdqu xmm3, [setearterceroyultimo0]
	pand xmm1, xmm3					;seteamos en 0 el 3er y 4to byte de cada dword.
	movdqu xmm3, [sumarultimo1]
	paddb xmm1, xmm3				;seteamos en 1 el 4to byte de cada dword.
	
	pxor xmm2, xmm2
	
	; if (index < 64)---------------------------------------------------------------------------------------------

	movdqu xmm4, xmm1				;copiamos el xmm1.
	movdqu xmm3, [invertirprimbyte]
	pxor xmm4, xmm3					;resto 255 - valor del primer byte de cada dword.
	
	;movups xmm4, [invertirprimbyte]
	
	movups xmm5, [doubles64]	; xmm5 = |  64 |  64 |  64 |  64 |		
	pcmpgtd xmm5, xmm7	; xmm5 = | T/F | T/F | T/F | T/F | (para 64 > index)
	
	pand xmm4, xmm5
	;movups xmm4, [invertirprimbyte]
	por xmm2, xmm4	; xmm2 = acumulador de resultados con mascaras aplicadas.

	; if (index >= 64 && index < 128)------------------------------------------------------------------------------------
	
	movdqu xmm4, xmm1
	movdqu xmm3, [setearsegundo255]
	por xmm4, xmm3					;seteamos el segundo byte de cada dword en 255.
		
		; Niego el xmm5 anterior y obtengo la que cumple (index >= 64)
	pcmpeqd xmm3, xmm3
	pxor xmm5, xmm3	; xmm5 = ¬xmm5 anterior.
	
	movdqu xmm6, [doubles128]	; xmm6 = | 128 | 128 | 128 | 128 | 
	pcmpgtd xmm6, xmm7	; xmm6 = | T/F | T/F | T/F | T/F | (para 128 > index)
	pand xmm5, xmm6		; xmm5 = | T/F | T/F | T/F | T/F | (para 128 > index && index>=64)
	pand xmm4, xmm5
	
	por xmm2, xmm4		; xmm2 = acumulador de resultados con mascaras aplicadas.
	
	; if (index >= 128 && index < 192)----------------------------------------------------------------------------------
	
	movdqu xmm4, xmm1				;copiamos el xmm1.
	movdqu xmm3, [suma1seg]
	paddusb xmm4, xmm3				;sumamos 1 al primer y segundo byte de cada dword.
	movdqu xmm3, [invertirprimysegbyte]
	pxor xmm4, xmm3					;resto 255 - valor del primer byte de cada dword (idem el segundo).
		
		; Niego el xmm6 anterior y obtengo la que cumple (index >= 128)
	pcmpeqd xmm3, xmm3
	pxor xmm6, xmm3	; xmm6 = ¬xmm6 anterior.
	
	movdqu xmm5, [doubles192]	; xmm5 = | 192 | 192 | 192 | 192 | 
	pcmpgtd xmm5, xmm7	; xmm5 = | T/F | T/F | T/F | T/F | (para 192 > index)
	pand xmm6, xmm5		; xmm6 = | T/F | T/F | T/F | T/F | (para 192 > index && index>=128)
	pand xmm4, xmm6
	
	por xmm2, xmm4		; xmm2 = acumulador de resultados con mascaras aplicadas.
		
	; if (index >= 192 && index < 256)-----------------------------------------------------------------------------------
	
	movdqu xmm4, xmm1
	movdqu xmm3, [setearsegundo0]
	pand xmm4, xmm3
		
		; Niego el xmm5 anterior y obtengo la que cumple (index >= 192)
	pcmpeqd xmm3, xmm3
	pxor xmm5, xmm3	; xmm5 = ¬xmm5 anterior.
	
	movdqu xmm0, [doubles256]	; xmm0 = | 256 | 256 | 256 | 256 |
	pcmpgtd xmm0, xmm7	; xmm0 = | T/F | T/F | T/F | T/F | (para 256 > index)
	pand xmm5, xmm0		; xmm5 = | T/F | T/F | T/F | T/F | (para 256 > index && index>=192)
	pand xmm4, xmm5
	
	por xmm2, xmm4		; xmm2 = acumulador de resultados con mascaras aplicadas.	
	
	; if (index >= 256)--------------------------------------------------------------------------------------------------
	
	pxor xmm4, xmm4
	movdqu xmm3, [sumarultimo1]
	paddusb xmm4, xmm3
		
		; Niego el xmm0 anterior y obtengo la que cumple (index >= 256)
	pcmpeqd xmm3, xmm3
	pxor xmm0, xmm3	; xmm0 = ¬xmm0 anterior.
	
	pand xmm4, xmm0
	por xmm2, xmm4		; xmm2 = acumulador de resultados con mascaras aplicadas.
			
		; Pongo el acumulador de resultados con mascaras aplicadas en la pantalla.
	
	push eax
	mov eax, ptr_img_actual
	movdqu [eax], xmm2
	add dword ptr_img_actual, 16
	pop eax
	
	add eax, 4							 
	add ebx, 4						
	
	mov word[vertical_1], bx			;vertical_1 += 1; 
	mov word[vertical_0], ax			;vertical_0 += 1;
	
	dec ecx
	cmp ecx, 0
	jne NEAR cicloplasmacolumnas	;(porque loop esta fuera de rango).
		
	add esi, 1
	add edi, 1
	
	mov word[horizontal_1], di				;horizontal_1 += 1;
	mov word[horizontal_0], si				;horizontal_0 += 1;
	
	pop edx
	dec edx
	cmp edx, 0
	jne NEAR cicloplasmafilas

	add word [vel_vertical_0], 4
	add word [vel_horizontal_0], 5

finplasma:
	pop ebx
	pop esi
	pop edi
	add esp, 4
	pop ebp
	ret
	
fin:
	pop ebx
	pop esi
	pop edi
	pop ebp
	ret	
